Skip to content

Conversation

@rintaro
Copy link
Member

@rintaro rintaro commented Jun 1, 2025

Part of #236 with minimal Sources/JExtractSwift changes. All the changes for it are going to be replaced with the remaining changes in #236 . This PR is mostly for reviewing SwiftKit changes.

Unify memory and instance management mechanism between value types (e.g. string or enum) and reference types (e.g. class and actor). Now all imported nominal types are allocated using the value witness table, are returned indirectly, and are destroyed in the same manner.

SwiftInstance is now the abstract base class for all the imported types including reference types. Concrete types can simply construct it by calling super(memorySegment, arena).

Unify memory and instance management mechanism between value types (e.g.
`string` or `enum`) and reference types (e.g. `class` and `actor`).
Now all imported nominal types are allocated using the value witness
table, are returned indirectly, and are destroyed in the same manner.

`SwiftInstance` is now the abstract base class for all the imported
types including reference types. Concrete types can simply construct it
by calling `super(memorySegment, arena)`.
Comment on lines -288 to +285
try (var arena = Arena.ofConfined()) {
// we need to make a pointer to the self pointer when calling witness table functions:
MemorySegment indirectDest = arena.allocate(SwiftValueLayout.SWIFT_POINTER);
MemorySegmentUtils.setSwiftPointerAddress(indirectDest, dest);
MemorySegment indirectSrc = arena.allocate(SwiftValueLayout.SWIFT_POINTER);
MemorySegmentUtils.setSwiftPointerAddress(indirectSrc, src);

var returnedDest = (MemorySegment) mh.invokeExact(indirectDest, indirectSrc, wtable);
return returnedDest;
try {
return (MemorySegment) mh.invokeExact(dest, src, wtable);
Copy link
Member Author

@rintaro rintaro Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This initializeWithCopy change was not included in #236. But I realized this has the same issue with destroy. No need for extra indirection anymore.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense

}

printer.printTypeDecl("public final class \(decl.javaClassName) implements \(parentProtocol)") {
printer.printTypeDecl("public final class \(decl.javaClassName) extends SwiftInstance implements \(parentProtocol)") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok 👍

\(decl.renderCommentSnippet ?? " *")
*/
public \(parentName.unqualifiedJavaTypeName)(\(renderJavaParamDecls(decl, paramPassingStyle: .wrapper))) {
this(/*arena=*/null, \(renderForwardJavaParams(decl, paramPassingStyle: .wrapper)));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should remove the constructors without an arena passed in actually… fine to keep in this pr, wdyt tho?

Copy link
Member Author

@rintaro rintaro Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with removing this constructor as we don't want users to use ofAuto() arena as much as possible.
Also mixing different arena in a session sounds scary 😅 E.g.

try(var arena = SwiftArena.ofConfined()) {
  var obj = new MyClass(arena);
  var value = new MyStruct(); // Accidental use of "auto" arena.
  obj.process(value); // Probably fine, but...
}

This is actually probably fine, but still it's not ideal.
Removing this convenience constructor prevents this kind of issues.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it’ll be more consistent to just always pass arenas, might save us weird headaches down the line.

you can remove here or we’ll do later, your call

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do it in this PR 👍

Comment on lines 37 to 43
// public SwiftAnyType(SwiftHeapObject object) {
// if (object.$layout().name().isEmpty()) {
// throw new IllegalArgumentException("SwiftHeapObject must have a mangled name in order to obtain its SwiftType.");
// }
//
// String mangledName = object.$layout().name().get();
// var type = SwiftKit.getTypeByMangledNameInEnvironment(mangledName);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel we need this function anymore. Every instance has $swiftType(). I don't even think object.$layout().name() is a mangled name (i.e. it's initialized with .withName(SwiftKit.nameOfSwiftType(typeMetadata, true));)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah let's remove, it is from the time when we were still calling directly into initializers from the java side I think

Users should consitently use the same arena. Also since nothing was
retaining the '.ofAuto()' arena was evil.
@rintaro rintaro force-pushed the jextract-value-or-reference branch from 91ca289 to 971bb92 Compare June 1, 2025 13:35
Because that seems to be more common
public \(parentName.unqualifiedJavaTypeName)(SwiftArena arena, \(renderJavaParamDecls(decl, paramPassingStyle: .wrapper))) {
var mh$ = \(descClassIdentifier).HANDLE;
try {
public \(parentName.unqualifiedJavaTypeName)(\(renderJavaParamDecls(decl, paramPassingStyle: .wrapper)), SwiftArena arena) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm 90% sure that arena parameter at the end is more common practice.
Although I haven't been able to find any wrapper constructor examples,

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last sounds ok me, makes the calls more similar to their swift equivalents and only the arena added on.

@rintaro rintaro merged commit 476087b into swiftlang:main Jun 2, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants